home *** CD-ROM | disk | FTP | other *** search
Oberon Text | 1994-07-11 | 12.7 KB | 297 lines | [.Ob./.Ob4] |
- Syntax10.Scn.Fnt
- MODULE ClipFrames; (* J. Templ, 30.10.90/28.6.91 *)
- (* ClipFrames.Frame provides basic drawing operations clipped on the frame borders.
- all drawing and mouse coordinates are relative to the origin x0, y0, which is relative to the
- top left corner of the frame. Capital letter coordinates always denote screen coordinates.
- In addition, ClipFrames contains two other useful frame classes, one for printing, and one
- for finding the bounding box*)
- IMPORT
- Oberon, Input, Display, Display1, Fonts, MenuViewers, TextFrames, GraphicOps, Texts, Printer;
- TYPE
- Frame* = POINTER TO FrameDesc;
- FrameDesc* = RECORD (Display.FrameDesc)
- col*, x0*, y0*, scale*: INTEGER;
- ext*: Frame;
- END ;
- PrintFrame* = POINTER TO PrintFrameDesc;
- PrintFrameDesc* = RECORD
- (FrameDesc)
- END ;
- BalloonFrame* = POINTER TO BalloonFrameDesc; (* inspired by B. Stamm *)
- BalloonFrameDesc* = RECORD
- (FrameDesc)
- END ;
- Lclip, Rclip, Bclip, Tclip: INTEGER; (* current clipping rectangle *)
- PROCEDURE Clip(F: Frame);
- BEGIN
- Lclip := F.X; Rclip := F.X + F.W; Bclip := F.Y; Tclip := F.Y + F.H
- END Clip;
- PROCEDURE Intersect(F: Frame; VAR X, Y, W, H: INTEGER): BOOLEAN;
- VAR t: INTEGER;
- BEGIN
- t := X + W;
- IF F.X > X THEN X := F.X END;
- IF F.X + F.W < t THEN W := F.X + F.W - X ELSE W := t - X END;
- IF W <= 0 THEN RETURN FALSE END;
- t := Y + H;
- IF F.Y > Y THEN Y := F.Y END;
- IF F.Y + F.H < t THEN H := F.Y + F.H - Y ELSE H := t - Y END;
- RETURN H > 0
- END Intersect;
- PROCEDURE MinMax(x, y: INTEGER; VAR min, max: INTEGER);
- BEGIN IF x < y THEN min := x; max := y ELSE min := y; max := x END
- END MinMax;
- PROCEDURE Update (F: Frame; x, y, w, h: INTEGER);
- BEGIN x := x + F.x0; y := y + F.y0;
- IF x < F.X THEN F.W := F.W + F.X - x; F.X := x END ;
- IF x + w > F.X + F.W THEN F.W := x + w - F.X END ;
- IF y < F.Y THEN F.H := F.H + F.Y - y; F.Y := y END ;
- IF y + h > F.Y + F.H THEN F.H := y + h - F.Y END
- END Update;
- (* ----------------- coordinate conversion methods ------------------ *)
- PROCEDURE (F: Frame) CX*(x: INTEGER): INTEGER;
- BEGIN RETURN F.X + (F.x0 + x) DIV F.scale
- END CX;
- PROCEDURE (F: Frame) CY*(y: INTEGER): INTEGER;
- BEGIN RETURN F.Y + F.H + (F.y0 + y) DIV F.scale
- END CY;
- PROCEDURE (F: Frame) Cx*(X: INTEGER): INTEGER;
- BEGIN RETURN (X - F.X) * F.scale - F.x0
- END Cx;
- PROCEDURE (F: Frame) Cy*(Y: INTEGER): INTEGER;
- BEGIN RETURN (Y - F.Y - F.H) * F.scale - F.y0
- END Cy;
- (* ----------------- screen drawing methods ------------------ *)
- PROCEDURE (F: Frame) DrawLine*(x1, y1, x2, y2, col, mode: INTEGER);
- BEGIN
- GraphicOps.Line(F, F.CX(x1), F.CY(y1), F.CX(x2), F.CY(y2), 1, Display1.ThisPattern(col), col)
- END DrawLine;
- PROCEDURE (F: Frame) DrawRect*(x, y, w, h, col, mode: INTEGER);
- BEGIN
- F.DrawLine(x, y, x+w, y, col, mode);
- F.DrawLine(x+w, y, x+w, y+h, col, mode);
- F.DrawLine(x, y+h, x+w, y+h, col, mode);
- F.DrawLine(x, y, x, y+h, col, mode);
- IF F.scale = 1 THEN
- F.DrawLine(x, y+1, x+w, y+1, col, mode);
- F.DrawLine(x, y+2, x+w, y+2, col, mode);
- F.DrawLine(x+w-1, y, x+w-1, y+h, col, mode);
- F.DrawLine(x+w-2, y, x+w-2, y+h, col, mode);
- F.DrawLine(x, y+h-1, x+w, y+h-1, col, mode);
- F.DrawLine(x, y+h-2, x+w, y+h-2, col, mode);
- F.DrawLine(x+1, y, x+1, y+h, col, mode);
- F.DrawLine(x+2, y, x+2, y+h, col, mode);
- END
- END DrawRect;
- PROCEDURE ClippedDot4(x1, x2, y1, y2, col, mode: INTEGER);
- BEGIN
- IF (Lclip <= x1) & (x1 < Rclip) THEN
- IF (Bclip <= y1) & (y1 < Tclip) THEN Display.ReplConst(col, x1, y1, 1, 1, mode) END;
- IF (Bclip <= y2) & (y2 < Tclip) THEN Display.ReplConst(col, x1, y2, 1, 1, mode) END
- END;
- IF (Lclip <= x2) & (x2 < Rclip) THEN
- IF (Bclip <= y1) & (y1 < Tclip) THEN Display.ReplConst(col, x2, y1, 1, 1, mode) END;
- IF (Bclip <= y2) & (y2 < Tclip) THEN Display.ReplConst(col, x2, y2, 1, 1, mode) END
- END
- END ClippedDot4;
- PROCEDURE (F: Frame) DrawCircle*(x, y, r, col, mode: INTEGER);
- VAR x1, y1, d, dx, dy: INTEGER;
- BEGIN
- Clip(F);
- x := F.CX(x); y := F.CY(y); r := r DIV F.scale;
- x1 := r; y1 := 0; dx := 8*(x1-1); dy := 8*y1+4; d := 1-4*r;
- WHILE x1 > y1 DO
- ClippedDot4(x-x1-1, x+x1, y-y1-1, y+y1, col, mode);
- ClippedDot4(x-y1-1, x+y1, y-x1-1, y+x1, col, mode);
- INC(d, dy); INC(dy, 8); INC(y1);
- IF d >= 0 THEN DEC(d, dx); DEC(dx, 8); DEC(x1) END
- END;
- IF x1 = y1 THEN ClippedDot4(x-x1-1, x+x1, y-y1-1, y+y1, col, mode) END
- END DrawCircle;
- PROCEDURE (F: Frame) DrawEllipse*(x, y, a, b, col, mode: INTEGER);
- VAR
- x1, y1: INTEGER;
- d, dx, dy, x2, y2, a1, a2, a8, b1, b2, b8: LONGINT;
- BEGIN
- Clip(F);
- x := F.CX(x); y := F.CY(y);
- IF (Lclip<=x+a) OR (x-a<=Rclip) OR (Bclip<=y+b) OR (y-b<=Tclip) THEN (* ellipse may be visible *)
- a1 := a; a2 := a1*a1; a8 := 8*a2; b1 := b; b2 := b1*b1; b8 := 8*b2;
- x1 := a; y1 := 0; x2 := a1*b2; y2 := 0; dx := b8*(a1-1); dy := 4*a2; d := b2*(1- 4*a1);
- WHILE y2 < x2 DO
- ClippedDot4(x-x1-1, x+x1, y-y1-1, y+y1, col, mode);
- INC(d, dy); INC(dy, a8); INC(y1); INC(y2, a2);
- IF d >= 0 THEN DEC(d, dx); DEC(dx, b8); DEC(x1); DEC(x2, b2) END
- END;
- INC(d, 4*(x2+y2)-b2+a2);
- WHILE x1 >= 0 DO
- ClippedDot4(x-x1-1, x+x1, y-y1-1, y+y1, col, mode);
- DEC(d, dx); DEC(dx, b8); DEC(x1);
- IF d < 0 THEN INC(d, dy); INC(dy, a8); INC(y1) END
- END
- END
- END DrawEllipse;
- PROCEDURE (F: Frame) DrawString*(x, y: INTEGER; s: ARRAY OF CHAR; font: Fonts.Font; col, mode: INTEGER);
- VAR ch: CHAR; pat: LONGINT; i, dx, chx, chy, chw, chh, chL, chB, chLOld, chBOld, chwOld, chhOld: INTEGER;
- BEGIN
- x := F.CX(x); y := F.CY(y);
- ch := s[0]; i := 0;
- WHILE ch # 0X DO
- Display.GetChar(font.raster, ch, dx, chx, chy, chw, chh, pat);
- chL := x+chx; chB := y+chy;
- chLOld := chL; chBOld := chB; chwOld := chw; chhOld := chh;
- IF Intersect(F, chL, chB, chw, chh) THEN
- IF (chw = chwOld) & (chh = chhOld) THEN
- Display.CopyPattern(col, pat, chL, chB, mode);
- ELSE
- Display.CopyBlock(chL, chB, chw, chh, chL-chLOld, -chhOld+chB-chBOld, Display.replace);
- Display.CopyPattern(col, pat, 0, -chhOld, mode);
- Display.CopyBlock(chL-chLOld, -chhOld+chB-chBOld, chw, chh, chL, chB, Display.replace)
- END
- END ;
- INC(x, dx * 4 DIV F.scale); INC(i); ch := s[i]
- END
- END DrawString;
- PROCEDURE (F: Frame) FillRect* (x, y, w, h, col, mode: INTEGER);
- BEGIN
- x := F.CX(x); y := F.CY(y); w := w DIV F.scale; h := h DIV F.scale;
- IF Intersect(F, x, y, w, h) THEN Display.ReplPattern(col, Display1.ThisPattern(col), x, y, w, h, mode) END
- END FillRect;
- PROCEDURE (F: Frame) FillCircle* (x, y, r, col, mode: INTEGER);
- BEGIN
- GraphicOps.Ellipse(F, F.CX(x), F.CY(y), r, r, 1, Display1.ThisPattern(col), col)
- END FillCircle;
- PROCEDURE (F: Frame) FillQuad* (x1, y1, x2, y2, x3, y3, x4, y4, col, mode: INTEGER); (* by B. Stamm *)
- TYPE LineParms = RECORD x,y,d,dx,dy,inx,iny,drawX,drawY: INTEGER END;
- VAR x,y,RHS2,RHS3: INTEGER; left,right: LineParms;
- PROCEDURE InitLineParms(x1,y1,x2,y2: INTEGER; VAR p: LineParms);
- BEGIN
- p.x := x1; p.dx := x2-x1; IF p.dx > 0 THEN p.inx := 1 ELSIF p.dx < 0 THEN p.inx := -1; p.dx := -p.dx ELSE p.inx := 0 END;
- p.y := y1; p.dy := y2-y1; IF p.dy > 0 THEN p.iny := 1 ELSIF p.dy < 0 THEN p.iny := -1; p.dy := -p.dy ELSE p.iny := 0 END;
- p.d := p.dy - p.dx; p.dx := 2*p.dx; p.dy := 2*p.dy;
- END InitLineParms;
- PROCEDURE LineStep(VAR p: LineParms);
- (* H = (d(x,y) := (2*x - 2*x1 + 1)*dy - (2*y - 2*y1 + 1)*dx < 0) *)
- BEGIN
- WHILE p.d < 0 DO INC(p.x,p.inx); INC(p.d,p.dy) END;
- p.drawX := p.x; p.drawY := p.iny DIV 2 + p.y;
- DEC(p.d,p.dx); INC(p.y,p.iny);
- END LineStep;
- BEGIN (* Quadrangle *)
- x1 := F.CX(x1); x2 := F.CX(x2); x3 := F.CX(x3); x4 := F.CX(x4);
- y1 := F.CY(y1); y2 := F.CY(y2); y3 := F.CY(y3); y4 := F.CY(y4);
- IF (y1>y2) OR (y1=y2) & (x1>x2) THEN x := x1; x1 := x2; x2 := x; y := y1; y1 := y2; y2 := y END;
- IF (y2>y3) OR (y2=y3) & (x2>x3) THEN x := x2; x2 := x3; x3 := x; y := y2; y2 := y3; y3 := y END;
- IF (y3>y4) OR (y3=y4) & (x3>x4) THEN x := x3; x3 := x4; x4 := x; y := y3; y3 := y4; y4 := y END;
- IF (y1>y2) OR (y1=y2) & (x1>x2) THEN x := x1; x1 := x2; x2 := x; y := y1; y1 := y2; y2 := y END;
- IF (y2>y3) OR (y2=y3) & (x2>x3) THEN x := x2; x2 := x3; x3 := x; y := y2; y2 := y3; y3 := y END;
- IF (y1>y2) OR (y1=y2) & (x1>x2) THEN x := x1; x1 := x2; x2 := x; y := y1; y1 := y2; y2 := y END;
- IF LONG(x2-x1)*LONG(y4-y1) > LONG(y2-y1)*LONG(x4-x1) THEN RHS2 := 2 ELSE RHS2 := 0 END;
- IF LONG(x3-x1)*LONG(y4-y1) > LONG(y3-y1)*LONG(x4-x1) THEN RHS3 := 1 ELSE RHS3 := 0 END;
- CASE RHS2 + RHS3 OF
- | 0: InitLineParms(x1,y1,x2,y2,left); InitLineParms(x1,y1,x4,y4,right);
- | 1: InitLineParms(x1,y1,x2,y2,left); InitLineParms(x1,y1,x3,y3,right);
- | 2: InitLineParms(x1,y1,x3,y3,left); InitLineParms(x1,y1,x2,y2,right);
- | 3: InitLineParms(x1,y1,x4,y4,left); InitLineParms(x1,y1,x2,y2,right);
- END;
- WHILE left.y # y2 DO
- LineStep(left); LineStep(right);
- F.DrawLine(F.Cx(left.drawX),F.Cy(left.drawY),F.Cx(right.drawX),F.Cy(left.drawY),col,mode)
- END;
- CASE RHS2 + RHS3 OF
- | 0: InitLineParms(x2,y2,x3,y3,left);
- | 1: InitLineParms(x2,y2,x4,y4,left);
- | 2: InitLineParms(x2,y2,x4,y4,right);
- | 3: InitLineParms(x2,y2,x3,y3,right);
- END;
- WHILE left.y # y3 DO
- LineStep(left); LineStep(right);
- F.DrawLine(F.Cx(left.drawX),F.Cy(left.drawY),F.Cx(right.drawX),F.Cy(left.drawY),col,mode)
- END;
- CASE RHS2 + RHS3 OF
- | 0,2: InitLineParms(x3,y3,x4,y4,left);
- | 1,3: InitLineParms(x3,y3,x4,y4,right);
- END;
- WHILE left.y # y4 DO
- LineStep(left); LineStep(right);
- F.DrawLine(F.Cx(left.drawX),F.Cy(left.drawY),F.Cx(right.drawX),F.Cy(left.drawY),col,mode)
- END
- END FillQuad;
- (* ----------------- printer drawing methods ------------------ *)
- PROCEDURE (F: PrintFrame) DrawRect* (x, y, w, h, col, mode: INTEGER);
- BEGIN
- x := F.CX(x)-1; y := F.CY(y)-1;
- Printer.ReplConst(x, y, w, 3);
- Printer.ReplConst(x+w, y, 3, h+3);
- Printer.ReplConst(x, y+h, w, 3);
- Printer.ReplConst(x, y, 3, h);
- END DrawRect;
- PROCEDURE (F: PrintFrame) DrawLine* (x1, y1, x2, y2, col, mode: INTEGER);
- BEGIN
- x1 := F.CX(x1); y1 := F.CY(y1);
- x2 := F.CX(x2); y2 := F.CY(y2);
- Printer.Line(x1, y1, x2, y2)
- END DrawLine;
- PROCEDURE (F: PrintFrame) DrawCircle* (x, y, r, col, mode: INTEGER);
- BEGIN Printer.Circle(F.CX(x), F.CY(y), r)
- END DrawCircle;
- PROCEDURE (F: PrintFrame) DrawEllipse* (x, y, a, b, col, mode: INTEGER);
- BEGIN Printer.Ellipse(F.CX(x), F.CY(y), a, b)
- END DrawEllipse;
- PROCEDURE (F: PrintFrame) DrawString* (x, y: INTEGER; s: ARRAY OF CHAR; font: Fonts.Font; col, mode: INTEGER);
- BEGIN
- Printer.String(F.CX(x), F.CY(y), s, font.name)
- END DrawString;
- PROCEDURE (F: PrintFrame) FillRect* (x, y, w, h, col, mode: INTEGER);
- BEGIN Printer.ReplPattern(F.CX(x), F.CY(y), w, h, col);
- END FillRect;
- PROCEDURE (F: PrintFrame) FillCircle* (x, y, r, col, mode: INTEGER);
- VAR error: ARRAY 32 OF CHAR;
- BEGIN error := "not yet implemented";
- HALT(99)
- END FillCircle;
- (* ----------------- methods for finding the bounding box------------------ *)
- PROCEDURE (F: BalloonFrame) DrawRect* (x, y, w, h, col, mode: INTEGER);
- BEGIN Update(F, x, y, w, h)
- END DrawRect;
- PROCEDURE (F: BalloonFrame) DrawLine* (x1, y1, x2, y2, col, mode: INTEGER);
- VAR minx, miny, maxx, maxy: INTEGER;
- BEGIN
- MinMax(x1, x2, minx, maxx);
- MinMax(y1, y2, miny, maxy);
- Update(F, minx, miny, maxx - minx, maxy - miny)
- END DrawLine;
- PROCEDURE (F: BalloonFrame) DrawCircle* (x, y, r, col, mode: INTEGER);
- BEGIN Update(F, x - r - 4 , y - r - 4, 2 * r + 4, 2 * r + 4)
- END DrawCircle;
- PROCEDURE (F: BalloonFrame) DrawEllipse* (x, y, a, b, col, mode: INTEGER);
- BEGIN Update(F, x - a - 4, y - b - 4, 2 * a + 4, 2 * b + 4)
- END DrawEllipse;
- PROCEDURE (F: BalloonFrame) DrawString* (x, y: INTEGER; s: ARRAY OF CHAR; font: Fonts.Font; col, mode: INTEGER);
- VAR i, w, dx, X, Y, W, H: INTEGER; p: LONGINT; ch: CHAR;
- BEGIN
- i := 0; w := 0; ch := s[0];
- WHILE ch # 0X DO Display.GetChar(font.raster, ch, dx, X, Y, W, H, p); INC(w, dx * 4); INC(i); ch := s[i] END ;
- Update(F, x, y, w, font.height*4)
- END DrawString;
- PROCEDURE (F: BalloonFrame) FillRect* (x, y, w, h, col, mode: INTEGER);
- BEGIN Update(F, x, y, w, h)
- END FillRect;
- PROCEDURE (F: BalloonFrame) FillCircle* (x, y, r, col, mode: INTEGER);
- BEGIN Update(F, x - r - 4 , y - r - 4, 2 * r + 4, 2 * r + 4)
- END FillCircle;
- PROCEDURE (F: BalloonFrame) FillQuad* (x1, y1, x2, y2, x3, y3, x4, y4, col, mode: INTEGER);
- BEGIN
- MinMax(x1, x2, x1, x2); MinMax(x2, x3, x2, x3); MinMax(x3, x4, x3, x4);
- MinMax(x2, x3, x2, x3); MinMax(x1, x2, x1, x2);
- MinMax(y1, y2, y1, y2); MinMax(y2, y3, y2, y3); MinMax(y3, y4, y3, y4);
- MinMax(y2, y3, y2, y3); MinMax(y1, y2, y1, y2);
- Update(F, x1, y1, x4 - x1, y4 - y1)
- END FillQuad;
- PROCEDURE InitBalloon*(F: BalloonFrame);
- BEGIN F.scale := 1;
- F.X := 10000; F.Y := 10000;
- F.W := -20000; F.H := -20000
- END InitBalloon;
- END ClipFrames.
-